Go 知识点(09)

您所在的位置:网站首页 select 阻塞 Go 知识点(09)

Go 知识点(09)

2024-02-02 05:20| 来源: 网络整理| 查看: 265

在使用select语句的时候,我们首先需要注意下面几个事情。

有默认分支,那么无论涉及通道操作的表达式是否有阻塞,select 语句都不会被阻塞。如果那几个表达式都阻塞了,或者说都没有满足求值的条件,那么默认分支就会被选中并执行。没有加入默认分支,那么一旦所有的 case 表达式都没有满足求值条件,那么 select 语句就会被阻塞。直到至少有一个 case 表达式满足条件为止。我们需要通过接收表达式的第二个结果值来判断通道是否已经关闭。一旦发现某个通道关闭了,我们就应该及时地屏蔽掉对应的分支或者采取其他措施。这对于程序逻辑和程序性能都是有好处的。select 语句只能对其中的每一个 case 表达式各求值一次。如果我们想连续或定时地操作其中的通道的话,就往往需要通过在 for 语句中嵌入 select 语句的方式实现。但这时要注意,简单地在 select 语句的分支中使用 break 语句,只能结束当前的 select 语句的执行,而并不会对外层的 for 语句产生作用。这种错误的用法可能会让这个 for 语句无休止地运行下去。 1. for select 作用于未关闭的通道 1.1 没有 default 分之场景

先看下面代码

func main() { ch := make(chan int, 3) go func() { time.Sleep(2 * time.Second) // 延迟往通道里里面发送数据 ch case v, ok := time.Sleep(2 * time.Second) // 延迟往通道里里面发送数据 ch case v, ok := time.Sleep(2 * time.Second) // 延迟往通道里里面发送数据 ch case v, ok := time.Sleep(2 * time.Second) // 延迟往通道里里面发送数据 ch case v, ok := fmt.Printf("v=%v, ok=%v\n", v, ok) time.Sleep(1 * time.Second) } default: fmt.Println("通道没有数据") time.Sleep(1 * time.Second) } fmt.Println("waiting") } }

输出结果如下:

通道没有数据 waiting 通道没有数据 waiting v=1, ok=true waiting 通道已经关闭 waiting 通道没有数据 waiting ...

会一直循环打印 default 分之的输出,那怎样跳出这个循环呢?

2.3 跳出 for select 循环语句 可以使用 goto 加 lable 跳转到 for 外面;可以设置一个额外的标记位,当 chan 关闭时,设置 flag=true ,在 for 的最后判断 flag 决定是否 break;

我们采用第二种方案:

func main() { ch := make(chan int, 3) go func() { time.Sleep(2 * time.Second) // 延迟往通道里里面发送数据 ch case v, ok := fmt.Printf("v=%v, ok=%v\n", v, ok) time.Sleep(1 * time.Second) } default: fmt.Println("通道没有数据") time.Sleep(1 * time.Second) } if exitFlag { fmt.Println("跳出循环") break } fmt.Println("waiting") } }

输出结果

通道没有数据 waiting 通道没有数据 waiting v=1, ok=true waiting 通道已经关闭 跳出循环

由以上示例我们可以得出以下结论:

select 语句中如果任意某个 case 的通道有值可读时,它就会被执行,其他 case 会被忽略;如果没有 default 语句,select 将有可能阻塞,直到某个 case 分之有值可以运行,所以 select 里最好有一个 default ,否则将有一直阻塞的风险;

如果 select 语句发现同时有多个候选分支满足选择条件,那么它就会用一种伪随机的算法在这些分支中选择一个并执行。

仅当 select 语句中的所有 case 表达式都被求值完毕后,它才会开始选择候选分支。这时候,它只会挑选满足选择条件的候选分支执行。如果所有的候选分支都不满足选择条件,那么默认分支就会被执行。如果这时没有默认分支,那么 select 语句就会立即进入阻塞状态,直到至少有一个候选分支满足选择条件为止。一旦有一个候选分支满足选择条件,select 语句就会被唤醒,这个候选分支就会被执行。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3